DevOps
CICD
K8s
Docker
在前一天介紹的Pod
、Deployment
物件其實是不能在網路上被"直接"存取到的,雖然它們都有各自的IP Address
,但這些 IP 僅有在 K8s cluster
內部才有辦法存取的到,若 K8s cluster
要提供對外服務,則需要透過第四層的port-forward
,將Pod
的Port
對應到Node
的Port
,expose給外部使用者。但若同時有多個 Pods
想要同時被存取時,就需要透過 Service
這個元件。
簡言之:
Service
就是K8s
提供讓集群內部Pod
和集群外世界溝通的一種方式。
可能大家會好奇,為甚麼要有Service
的設計?為甚麼不能讓外部直接存取Pod
的IP?還要透過Service
? 原因有二:
Pod
可能很多,例如一個Deployment
下的所有Pod
,還有之後會介紹的Ingress
,Service
可以透過 "Selector" 同時選取所有物件,在實務上很方便Pod
其實是經常重啟的,一旦Pod
重啟,每次的IP都會跟著變動,為了防止每次重啟Pod
就要更改一次設定,就需要有個"東西"來幫我們找到重啟後的Pod
,這個"東西"就是Service
Service
的YAML範例如下:
$ vim svc.yaml
apiVersion: v1
kind: Service
metadata:
name: my-service
spec:
selector:
app: MyApp
ports:
- protocol: TCP
port: 80
targetPort: 9376
創建Service
$ kubectl apply -f svc.yaml
我們看一下其中的欄位設定:
Service
要適用到哪些 Pod
,依據label: app=MyApp
來選取port-forward
的設定,指定Pod
的Port
對應到的Node
的Port
,下面會有詳細介紹上述是第一種Service
創建方式 (透過YAML),還有第二種創建Service
的方法,即透過kubectl expose
:
$ kubectl expose po <pod-name> --name=<svc-name> --type=<type-of-svc>
這種方法是將Pod
expose給外部使用者,相當於創建一個Service
。創建的Service
會自動將該Pod
的label
填入selector
欄位,name
欄位則輸入Service
的名稱,type
是Service
的類別。
沒錯,
Service
是有類別區分的喔,依照不同功能及使用場景,共有三種類別。
Service依照不同功能及使用場景,共有三種Service
:NodePort
, ClusterIP
及LoadBlancer
NodePort
的目標是將Pod
expose給外部使用者。在Node
上開放一個特定Port
,再透過Service
將port mapping到Pod
的Port
,如下圖
Node
要開放哪個Port
,Service
會將此Port
mapping到Pod
的Port
上。NodePort
範圍是30000 ~ 32767,若NodePort
欄位沒有給定,K8s
會自動assign一個範圍內的Port
為NodePort
Service
上的Cluster IP
的Port
,此Port
會和targetPort
作 mapping。port
通常會指定為80
Service
可以想像成一個Cluster之中的Virtual Server
,這個Virtual Server
會擁有自己的IP,這個IP稱為Cluster IP
Pod
上允許外部資源存取的 Port Number,Service
會將request forward到這個Port。若在YAML中沒有給定targetPort
,則K8s
會設定為和port
相同的值NodePort
的YAML範例如下:
$ vim NP-Svc.yaml
apiVersion: v1
kind: Service
metadata:
name: nodeport-service
spec:
type: NodePort
ports:
- targetPort: 80
port: 80
nodePort: 30008
selector:
app: MyApp
ClusterIP
是K8s
default的Service Type
,它只提供集群內部的服務,集群內的Pod
都可以透過它互相訪問,集群外部則無法訪問它
若創建
Service
時沒有定義type,K8s
會默認為ClusterIP
ClusterIP
的應用場景通常是保護某些資料不被外部存取,例如一個Web Application有back-end和front-end,我只想將front-end Pod expose出去,但又想back-end和front-end可以溝通,這時就可以用到ClusterIP Service
ClusterIP
的YAML範例如下:
$ vim CIP-Svc.yaml
apiVersion: v1
kind: Service
metadata:
name: clusterip-service
spec:
type: NodePort
ports:
- targetPort: 80
port: 80
selector:
app: MyApp
LoadBalancer
服務expose到 Internet 的標準方式。所有通往指定的Port
的流量都會被forward到對應的服務。它沒有過濾條件,沒有路由等。也就是說,你可以發送任何種類的流量到該服務,像 HTTP,TCP,UDP,Websocket,gRPC 或其它種類。這個方式的最大缺點是每一個用 LoadBalancer
暴露的服務都會有它自己的 IP ,每個用到的 LoadBalancer
都需要付費,所以LoadBalancer
通常會和Ingress
一起使用。
因為
LoadBalancer
通常會和Ingress
一起使用,而Ingress
又比較複雜,有機會的話之後再介紹
事實上,
Service
不是存在於任一Node
的物件,它是屬於Cluster based
的resource-object
,因此當Service
在select Pod時,才可以選到其他Node
的Pod
今天介紹了Service
這個物件,因為Service
內容比較多,如果不拉一天介紹的話感覺不太能銜接後面會遇到的題目,所以特別介紹一下。好啦,今天就到這囉~ 謝謝大家~
Service
Kubernetes - Services Explained in 15 Minutes!
[Kubernetes] How to Implement Kubernetes Service - ClusterIP
KubernetesService Overview
You can find me on